import serial
import time
import os
import sys
import random
import re
import subprocess
import threading



# 定义常量
DEBUG_PORT = "COM4"
AT_PORT = "COM42"
BAUDRATE = 115200
# 定义变量
at_serial = None
debug_serial = None
#记录运行次数
runTimes		= 0
#log文件
DEBUG_LOG = ""
ADB_LOG = ""
AT_LOG = ""

# 创建日志文件
def createLogFile():
    global DEBUG_LOG, ADB_LOG, AT_LOG
    timestamp = time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime())
    DEBUG_LOG = f"DEBUG_LOG_{timestamp}.log"
    ADB_LOG = f"ADB_LOG_{timestamp}.log"
    AT_LOG = f"AT_LOG_{timestamp}.log"
    
    with open(DEBUG_LOG, 'w', encoding='utf-8') as file:
        file.write("DEBUG 日志开始记录...\n")
    
    with open(ADB_LOG, 'w', encoding='utf-8') as file:
        file.write("ADB 日志开始记录...\n")
        
    with open(AT_LOG, 'w', encoding='utf-8') as file:
        file.write("AT 日志开始记录...\n")
        
# 写日志
def write_log(log, logFile):
    with open(logFile, 'a', encoding='utf-8') as file_object:
        file_object.write(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + log + "\r\n")
        now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        print("[" + now_time+ "]" + " " + log)

#Send at instruction
def at_write(command, timeout, at_port_opened, at_result,RDY=0,CPIN=0):
	at_command = command.encode("UTF-8")
	at_port_opened.write(at_command)
 
#读取at口返回
def at_read(serial_port, logFile=""):
 rec_str = ''
 while (True):
  time.sleep(1)
  lenth = serial_port.inWaiting()
  if lenth > 0:
   rec_str = serial_port.read(size=lenth)
   try:
    rec_str = re.sub('\\x1b.*?m', "", rec_str.decode("UTF-8"), 0, re.I)
    if logFile != "":
     with open(logFile, 'a') as file_object:
      rec_str = str(time.time()) + ":" + str(
       time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + rec_str
      file_object.write(
       str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + rec_str + "\r\n")
    return rec_str
   except:
    return ""
  else:
   break
 return rec_str

# 登录设备
def loginDevice():
 global DEBUG_LOG
 #确认登录失败的条件，或者，不可能失败
 while True:
#   print("等待登录... ... ")
  write_log("等待登录... ... ", DEBUG_LOG)
  time.sleep(3)
  at_write("\r\n",3,debug_serial,"OK")
  result = at_read(debug_serial)

  with open(DEBUG_LOG, 'a') as file_object:
   file_object.write(result)

  if "login:" in result:
   at_write("root\r\n",3,debug_serial,"OK")
#    print("账号输入成功")
   write_log("账号输入成功", DEBUG_LOG)
   time.sleep(2)
   at_write("oelinux123\r\n",3,debug_serial,"OK")
#    print("密码输入成功")
   write_log("密码输入成功", DEBUG_LOG)
  elif "~ #" in result:
#    print("登录成功")
   write_log("登录成功", DEBUG_LOG)
   break
  else:
   continue 

#检查debug口通信状态
def check_port_status():
 global debug_serial
 if debug_serial == None:
  try:
   debug_serial = serial.Serial(DEBUG_PORT,BAUDRATE)
  except:
   print("端口连接失败，请检查端口")
   sys.exit()

# 写入运行次数到日志
def writeRuntimesToLog():
 global runTimes
 with open(DEBUG_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
#  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 with open(AT_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
#  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 with open(ADB_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 runTimes += 1
 
#发送AT指令
def send_at_command(command):
        # 打开串口
        ser = serial.Serial(AT_PORT, BAUDRATE)
        ser.write((command + "\r\n").encode())
        ser.write(("\r\n").encode())
        time.sleep(6)
        response = ser.read_all().decode()
        ser.close()
        # write_log(f"at指令{command}执行结果:{response}",AT_LOG)
        with open(AT_LOG, 'a', encoding='utf-8') as file_object:
            file_object.write(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + response + "\r\n")
        return response
        
# 发送adb命令
def send_adb_command(command):
    try:
        # 开启adb root
        subprocess.run(["adb", "root"], capture_output=True, text=True)
        # 使用 subprocess 模块执行 adb shell 命令
        result = subprocess.run(
            ["adb", "shell", command], capture_output=True, text=True
        )
        with open(ADB_LOG, "a", encoding="utf-8") as file_object:
            file_object.write(
                str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                + "\r\n"
                + result.stdout
                + "\r\n"
            )
        # 返回命令的输出结果
        return result.stdout
    except Exception as e:
        return str(e)

# 写入运行次数到日志
def writeRuntimesToLog():
    global runTimes
    with open(DEBUG_LOG, 'a+') as file_object:
        file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20, runTimes, ">"*20))
    print("\r\n{} runtimes: {} {}\r\n".format("<"*20, runTimes, ">"*20))
    runTimes += 1

# 进入测试接口
def intoTestInterface_testsdk(debug_serial, logFile):
    at_write("cd /data\r\n./test_sdk_api\r\n", 3, debug_serial, "OK")
    write_log("进入datacall测试接口", logFile)
    time.sleep(3)
    at_write("0\n", 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("0\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    result = at_read(debug_serial, logFile)

# 退出测试接口
def exit_testsdk(debug_serial, logFile):
    at_write("-1\n-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)

# 返回测试接口
def back_testsdk(debug_serial, logFile):
    write_log("返回测试接口", logFile)
    at_write("-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)
#创建测试APN
def set_apn_testsdk(testapn,testapn_name):
    write_log(f"开始创建测试APN{testapn}，名称{testapn_name}", DEBUG_LOG)
    time.sleep(3)
    at_write("10\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(testapn),3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("3\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("3\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(testapn_name),3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    result=at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"测试APN{testapn}创建成功", DEBUG_LOG)
    else:
        write_log(f"测试APN{testapn}创建失败", DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)

#设置并启动datacall
def set_datacall1_testsdk(datacall_id,datacall_name,testapn):
    write_log(f"开始设置datacall{datacall_id}，名称{datacall_name}设置的APN为{testapn}路", DEBUG_LOG)
    time.sleep(1)
    at_write("1\n", 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("{}\n".format(datacall_name),3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("1\n",3 , debug_serial, "OK")
    time.sleep(3)
    result1 = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result1:
        write_log(f"datacall{datacall_id}创建成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}创建失败", DEBUG_LOG)
    
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("2\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_write("{}\n".format(datacall_id), 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(testapn),3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("1\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("0\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("y\n",3 , debug_serial, "OK")
    time.sleep(3)
    result2 =at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result2:
        write_log(f"datacall{datacall_id}设置APN{testapn}成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}设置APN{testapn}失败", DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
#启动datacall
def start_datacall_testsdk(datacall_id):
    write_log(f"开始拨号datacall：{datacall_id}", DEBUG_LOG)
    at_write("4\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(3)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"datacall{datacall_id}拨号成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}拨号失败", DEBUG_LOG)
    at_write("8\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(5)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)

#删除datacall
def remove_datacall_testsdk(datacall_id):
    time.sleep(3)
    write_log(f"开始停止并删除datacall：{datacall_id}", DEBUG_LOG)
    at_write("5\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("6\n",3 , debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(3)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"datacall{datacall_id}删除成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}删除失败", DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(3)
    


   

            
# ql_dm_set_air_plane_mode 多次开关飞行模式
def ql_dm_set_air_plane_mode():
    write_log(f"进入DM测试接口", DEBUG_LOG)
    time.sleep(3)
    at_write("7\n", 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("0\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    write_log(f"开始开关飞行模式", DEBUG_LOG)
    time.sleep(3)
    at_write("12\n",3 , debug_serial, "OK")
    result = at_read(debug_serial, DEBUG_LOG)
    print(result)
    if "OFF" in result:
        write_log(f"飞行模式已关闭", DEBUG_LOG)
        flag = 1
    if "ON" in result:
        write_log(f"飞行模式已开启", DEBUG_LOG)
        flag = 2
    time.sleep(3)
    time.sleep(3)
    at_write("13\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(flag),3 , debug_serial, "OK")
    time.sleep(3)
    at_write("12\n",3 , debug_serial, "OK")
    result = at_read(debug_serial, DEBUG_LOG)
    print(result)
    if "OFF" in result:
        write_log(f"飞行模式已关闭", DEBUG_LOG)
    if "ON" in result:
        write_log(f"飞行模式已开启", DEBUG_LOG)
    time.sleep(3)

    
def route_config(commands):
    for command in commands:
        result = send_adb_command(command)
        write_log(f"{command} 命令执行结果：\r\n{result}",ADB_LOG)   
        
def check_ql_netd_memory():
    time.sleep(3)
    write_log(f"开始检查ql_netd内存占用情况", ADB_LOG)
    result = send_adb_command("top -d 1 -m -n 10 | grep ql_netd")
    write_log(f"ql_netd内存占用情况：\r\n{result}", ADB_LOG)
def check_ql_netd_memory_periodically():
    while True:
        check_ql_netd_memory()
        time.sleep(10) 
# 测试主函数
def main():
    #路由配置，根据插入的sim卡情况进行配置
    commands = [
        "ip route add default via 10.135.87.190 dev rmnet_data0",
        "iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE --random",
        "echo 'nameserver 211.138.180.5'>> /tmp/ql_lan_resolv.conf",
        "echo 'nameserver 211.138.180.4'>> /etc/resolv.conf",
    ]
    # APN 和 Datacall 配置信息
    apn_configs = [
        {"id": "9", "name": "test1"},
        {"id": "11", "name": "test2"}
    ]
    datacall_configs = [
        {"id": "1", "name": "call1", "apn_id": "9"},
        {"id": "2", "name": "call2", "apn_id": "11"}
    ]
    """这里可以自行配置想要创建和拨号的APN和Datacall信息"""
    
    
    # 初始化步骤
    check_port_status()
    createLogFile()
    print(f"DEBUG_LOG: {DEBUG_LOG}, ADB_LOG: {ADB_LOG}, AT_LOG: {AT_LOG}")
    loginDevice()
    intoTestInterface_testsdk(debug_serial, DEBUG_LOG)

    # 配置 APN 和 Datacall
    for apn in apn_configs:
        set_apn_testsdk(apn["id"], apn["name"])

    for datacall in datacall_configs:
        set_datacall1_testsdk(datacall["id"], datacall["name"], datacall["apn_id"])
        start_datacall_testsdk(datacall["id"])

    # 配置路由
    # route_config(commands)
    # 启动内存占用检查线程
    memory_thread = threading.Thread(target=check_ql_netd_memory_periodically, daemon=True)
    memory_thread.start()
    
    # 退出测试模式并进入飞行模式，开关循环
    back_testsdk(debug_serial, DEBUG_LOG)
    while True:
        ql_dm_set_air_plane_mode()
    

       
# 主程序
if __name__ == '__main__':
    main()